package com.tulingdemo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@Slf4j
public class AsyncExecutorConfig {
        // 核心线程数（setCorePoolSize）：线程池创建时候初始化的线程数
        // 最大线程数（setMaxPoolSize）：线程池最大的线程数，只有在缓冲队列满了之后才会申请超过核心线程数的线程
        // 缓冲队列（setQueueCapacity）：用来缓冲执行任务的队列
        // 允许线程的空闲时间（setKeepAliveSeconds）：当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        // 线程池名的前缀（setThreadNamePrefix）：设置好了之后可以方便我们定位处理任务所在的线程池
        // 线程池对拒绝任务的处理策略（setRejectedExecutionHandler）
        // 方法的调用线程中运行被拒绝的任务（setWaitForTasksToCompleteOnShutdown）；如果执行程序已关闭，则会丢弃该任务
        // setWaitForTasksToCompleteOnShutdown（true）该方法就是这里的关键，用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean，这样这些异步任务的销毁就会先于异步线程池的销毁。
        // 同时，这里还设置了setAwaitTerminationSeconds(60)，该方法用来设置线程池中任务的等待时间，如果超过这个时候还没有销毁就强制销毁，以确保应用最后能够被关闭，而不是阻塞住。
        @Bean("asyncExecutor")
        public Executor asyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            int curSystemThreads = Runtime.getRuntime().availableProcessors();
            curSystemThreads = curSystemThreads > 8 ? curSystemThreads + 1 : 9;
            executor.setCorePoolSize(curSystemThreads);
            executor.setMaxPoolSize(curSystemThreads << 2);
            executor.setQueueCapacity(1000);
            executor.setKeepAliveSeconds(60);
            executor.setThreadNamePrefix("Spring Async Executor-");
            executor.setRejectedExecutionHandler(
                    (runnable, threadPoolExecutor) -> {
                        try {
                            threadPoolExecutor.getQueue().put(runnable);
                            log.info("Add Thread pool");
                        } catch (InterruptedException e) {
                            log.info("Thread pool receives InterruptedException: " + e);
                        }
                    });
            executor.setWaitForTasksToCompleteOnShutdown(true);
            executor.setAwaitTerminationSeconds(60);
            return executor;
        }
        @Bean
        public Executor otherExecutor() {
            return new ThreadPoolTaskExecutor();
        }
    }